﻿using KongMing.Project.Entity.Business;
using KongMing.Project.Entity.Common;
using KongMing.Project.Entity.Dto;
using KongMing.Project.Entity.View;
using KongMing.Project.IService.Business;
using KongMing.Project.Common;
using SqlSugar;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Primitives;
using KongMing.Project.Common.Sdk;
using Microsoft.Extensions.Options;

namespace KongMing.Project.Service.Business
{
    public class BookService : BaseService, IBookService
    {
        private RedisConfig _redisConfig;
        public BookService(IServiceProvider serviceProvider, IOptionsMonitor<RedisConfig> redisConfig) : base(serviceProvider)
        {
            _redisConfig = redisConfig.CurrentValue;
        }

        public async Task<Book_V> BookDetailAsync(string bookId)
        {
            bookId.CheckNull(msg: "参数不可为空！");
            var book = await BusinessDB.Queryable<Book>().InSingleAsync(bookId);
            book.CheckNull(msg: "找不到图书信息！");
            return new Book_V
            {
                BookId = bookId,
                Sn = book.Sn,
                Title = book.Title,
                Author = book.Author,
                Description = book.Description,
                InPrice = book.InPrice,
                SellPrice = book.SellPrice
            };
        }

        public async Task BookSaveAsync(Book_R book)
        {
            book.CheckNull(msg: "图书信息不可为空！");
            book.Title.CheckNull(msg: "书名不可为空！");
            if (string.IsNullOrWhiteSpace(book.BookId))
            {
                var db_book = new Book()
                {
                    BookId = Tools.GUID,
                    Title = book.Title,
                    Author = book.Author,
                    Description = book.Description,
                    InPrice = book.InPrice ?? 0,
                    SellPrice = book.SellPrice ?? 0,
                    CreateTime = Configs.NowTime,
                    CreateUserId = ApiUserContext.UserId ?? "",
                    CreateUserName = ApiUserContext.UserName ?? ""
                };
                await BusinessDB.Insertable(db_book).ExecuteCommandAsync();
            }
            else
            {
                var db_book = await BusinessDB.Queryable<Book>().InSingleAsync(book.BookId);
                db_book.CheckNull(msg: "找不到图书信息！");
                db_book.Title = book.Title;
                db_book.Author = book.Author;
                db_book.Description = book.Description;
                db_book.InPrice = book.InPrice ?? 0;
                db_book.SellPrice = book.SellPrice ?? 0;
                await BusinessDB.Updateable(db_book).ExecuteCommandAsync();
            }
        }

        public Task<QueryResult<Book_V>> BookQueryAsync(QueryModel<Book_R> query)
        {
            return BookQuery_RedisCache(query);
        }

        public async Task<QueryResult<Book_V>> BookQuery_Normal(QueryModel<Book_R> query)
        {
            query.PageIndex = Math.Max(1, query.PageIndex);
            query.PageSize = Math.Max(20, query.PageSize);
            var whereExp = Expressionable.Create<Book>();
            var book = query.Model;
            RefAsync<int> count = 0;
            if (book != null)
            {
                whereExp.AndIF(!string.IsNullOrWhiteSpace(book.Title), x => x.Title.Contains(book.Title))
                    .AndIF(!string.IsNullOrWhiteSpace(book.Author), x => x.Author.Contains(book.Author))
                    .AndIF(book.InPrice != null, x => x.InPrice == book.InPrice);
            }
            string orderStr = string.IsNullOrWhiteSpace(query.GetOrderStr()) ? " CreateTime desc " : query.GetOrderStr();
            var books = await BusinessDB.Queryable<Book>().Where(whereExp.ToExpression()).Select<Book_V>().OrderBy(orderStr).ToPageListAsync(query.PageIndex, query.PageSize, count);
            var result = new QueryResult<Book_V>()
            {
                PageIndex = query.PageIndex,
                PageSize = query.PageSize,
                DataCount = count,
                Data = books
            };
            result.ChangePageCount();
            return result;
        }

        /// <summary>
        /// 使用本地缓存查询，示例
        /// </summary>
        public async Task<QueryResult<Book_V>> BookQuery_MemoryCache(QueryModel<Book_R> query)
        {
            query.PageIndex = Math.Max(1, query.PageIndex);
            query.PageSize = Math.Max(20, query.PageSize);
            //将查询条件计算hash值，如果查询条件不变，只变了分页，总数据就从缓存中取
            string hashKey = Tools.ComputeHash(JsonConvert.SerializeObject(query.OrderItems) + JsonConvert.SerializeObject(query.Model));
            string cacheKey = "km_querydata_book_" + hashKey;
            var books = new List<Book_V>();
            if (!MCache.TryGetValue(cacheKey, out books))
            {
                //使用场景：拿到全部数据，然后对数据进行处理之后再做分页（例如：只对某列去重，然后返回去重后的总数并且分页）
                var whereExp = Expressionable.Create<Book>();
                var book = query.Model;
                if (book != null)
                {
                    whereExp.AndIF(!string.IsNullOrWhiteSpace(book.Title), x => x.Title.Contains(book.Title))
                        .AndIF(!string.IsNullOrWhiteSpace(book.Author), x => x.Author.Contains(book.Author))
                        .AndIF(book.InPrice != 0, x => x.InPrice == book.InPrice);
                }
                string orderStr = string.IsNullOrWhiteSpace(query.GetOrderStr()) ? " CreateTime desc " : query.GetOrderStr();
                books = await BusinessDB.Queryable<Book>().Select<Book_V>().OrderBy(orderStr).ToListAsync();
                //设置过期时间
                var cts = new CancellationTokenSource(TimeSpan.FromSeconds(50));
                var cacheEntryOptions = new MemoryCacheEntryOptions().AddExpirationToken(new CancellationChangeToken(cts.Token));
                MCache.Set(cacheKey, books, cacheEntryOptions);
            }
            var result = new QueryResult<Book_V>()
            {
                PageIndex = query.PageIndex,
                PageSize = query.PageSize,
                DataCount = books.Count,
                Data = books ?? books.Skip((query.PageIndex - 1) * query.PageSize).Take(query.PageSize).ToList()
            };
            result.ChangePageCount();
            return result;
        }

        /// <summary>
        /// 使用Redis缓存查询，示例
        /// </summary>
        public async Task<QueryResult<Book_V>> BookQuery_RedisCache(QueryModel<Book_R> query)
        {
            query.PageIndex = Math.Max(1, query.PageIndex);
            query.PageSize = Math.Max(20, query.PageSize);
            //将查询条件计算hash值，如果查询条件不变，只变了分页，总数据就从缓存中取
            string hashKey = Tools.ComputeHash(JsonConvert.SerializeObject(query.Model));
            string redisKey = "km_querydata_book_" + hashKey;
            var books = new List<Book_V>();
            using var redisClient = new RedisClient(_redisConfig);
            var rdb = redisClient.GetDatabase();

            var _value = await rdb.StringGetAsync(redisKey);

            if (!_value.HasValue)
            {
                //使用场景：拿到全部数据，然后对数据进行处理之后再做分页（例如：只对某列去重，然后返回去重后的总数并且分页）
                var whereExp = Expressionable.Create<Book>();
                var book = query.Model;
                if (book != null)
                {
                    whereExp.AndIF(!string.IsNullOrWhiteSpace(book.Title), x => x.Title.Contains(book.Title))
                        .AndIF(!string.IsNullOrWhiteSpace(book.Author), x => x.Author.Contains(book.Author))
                        .AndIF(book.InPrice != 0, x => x.InPrice == book.InPrice);
                }
                string orderStr = string.IsNullOrWhiteSpace(query.GetOrderStr()) ? " CreateTime desc " : query.GetOrderStr();
                books = await BusinessDB.Queryable<Book>().Select<Book_V>().OrderBy(orderStr).ToListAsync();
                await rdb.StringSetAsync(redisKey, JsonConvert.SerializeObject(books), TimeSpan.FromSeconds(50));
            }
            else
                books = JsonConvert.DeserializeObject<List<Book_V>>(_value);

            var result = new QueryResult<Book_V>()
            {
                PageIndex = query.PageIndex,
                PageSize = query.PageSize,
                DataCount = books.Count,
                Data = books ?? books.Skip((query.PageIndex - 1) * query.PageSize).Take(query.PageSize).ToList()
            };
            result.ChangePageCount();
            return result;
        }
    }
}
